package com.one.square.common.zookeeper.lock;

import com.one.square.core.constant.GlobalConstants;
import com.one.square.core.exception.LockException;
import com.one.square.core.lock.DistributedLock;
import com.one.square.core.lock.OneSquareLock;
import lombok.AllArgsConstructor;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.recipes.locks.InterProcessMutex;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;

import java.util.concurrent.TimeUnit;

/**
 * @author cwm
 * @Description zookeeper分布式锁实现
 * @date 2021/10/29 下午12:45
 * @Version 1.0
 */
@AllArgsConstructor
public class ZookeeperDistributedLock implements DistributedLock {
    private final  CuratorFramework client;


    private OneSquareLock getLock(String key) {
        InterProcessMutex lock = new InterProcessMutex(client, getPath(key));
        return new OneSquareLock(lock, this);
    }

    @Override
    public OneSquareLock lock(String key, long leaseTime, TimeUnit unit, boolean isFair) throws Exception {
        OneSquareLock zLock = this.getLock(key);
        InterProcessMutex ipm = (InterProcessMutex)zLock.getLock();
        ipm.acquire();
        return zLock;
    }

    @Override
    public OneSquareLock tryLock(String key, long waitTime, long leaseTime, TimeUnit unit, boolean isFair) throws Exception {
        OneSquareLock zLock = this.getLock(key);
        InterProcessMutex ipm = (InterProcessMutex)zLock.getLock();
        if (ipm.acquire(waitTime, unit)) {
            return zLock;
        }
        return null;
    }

    @Override
    public void unlock(Object lock) throws Exception {
        if (lock != null) {
            if (lock instanceof InterProcessMutex) {
                InterProcessMutex ipm = (InterProcessMutex)lock;
                if (ipm.isAcquiredInThisProcess()) {
                    ipm.release();
                }
            } else {
                throw new LockException("requires InterProcessMutex type");
            }
        }
    }

    private String getPath(String key) {
        return GlobalConstants.PATH_SPLIT + GlobalConstants.LOCK_KEY_PREFIX + GlobalConstants.PATH_SPLIT + key;
    }
}
